#include "MemTable.hpp"

struct MemIndex *MemTable::QueryExecuteSchedule( struct MemField *where_field_array , size_t where_field_array_count )
{
	unordered_map<string,MemIndex*>::iterator	it ;
	struct MemIndex					*index = NULL ;
	size_t						index_field_array_no ;
	size_t						index_field_array_count ;
	struct MemField					*index_field = NULL ;
	
	for( it = indexs.begin() ; it != indexs.end() ; it++ )
	{
		index = it->second ;
		index_field_array_count = index->GetIndexFieldArrayCount() ;
		if( index_field_array_count != where_field_array_count )
			continue;
		
		for( index_field_array_no = 0 , index_field = index->GetIndexFieldArray()
			; index_field_array_no < index_field_array_count
			; index_field_array_no++ , index_field++ , where_field_array++ )
		{
			if( ! ( index_field->field_offset == where_field_array[index_field_array_no].field_offset && index_field->field_size == where_field_array[index_field_array_no].field_size ) )
			{
				break;
			}
			else
			{
			}
		}
		if( index_field_array_no >= index_field_array_count )
		{
			break;
		}
		else
		{
		}
	}
	if( it == indexs.end() )
	{
		index = NULL ;
	}
	else
	{
	}
	
	return index;
}

bool MemTable::TestRecordMatched( char *record_data , struct MemField *where_field_array , size_t where_field_array_count , void *record_buffer )
{
	size_t		where_field_array_no ;
	int		result ;
	
	for( where_field_array_no = 0 ; where_field_array_no < where_field_array_count ; where_field_array_no++ )
	{
		result = memcmp( (char*)record_buffer+where_field_array[where_field_array_no].field_offset , record_data+where_field_array[where_field_array_no].field_offset , where_field_array[where_field_array_no].field_size ) ;
		if( result )
			return false;
	}
	
	return true;
}

MemTable::MemTable( MemDatabase *db , string table_name , size_t record_size )
{
	this->db = db ;
	
	this->table_name = table_name ;
	this->record_size = record_size ;
	
	this->max_record_no = 1 ;
	
	return;
}

MemTable::~MemTable()
{
	struct MemDataPage	*record_datapage = NULL ;
	
	for( list<MemDataPage*>::iterator it = record_data_pages.begin() ; it != record_data_pages.end() ; )
	{
		record_datapage = (*it) ;
#if MDB_TRACE
		cout << "TRACE - MemTable::~MemTable() : free record datapage[" << static_cast<void*>(record_datapage) << "]" << endl ;
#endif
		record_data_pages.erase( it++ );
		free(record_datapage);
	}
	
	for( unordered_map<string,MemIndex*>::iterator it = indexs.begin() ; it != indexs.end() ; )
	{
#if MDB_TRACE
		string	index_name = it->second->GetIndexName() ;
#endif
		delete it->second;
		indexs.erase( it++ );
#if MDB_TRACE
		cout << "TRACE - MemTable::~MemTable() : delete index[" << index_name << "]" << endl ;
#endif
	}
	
	return;
}

string MemTable::GetTableName()
{
	return table_name;
}

size_t MemTable::GetRecordSize()
{
	return record_size;
}

size_t MemTable::GetMaxRecordNo()
{
	return max_record_no;
}

char *MemTable::QueryRecordWithoutIndex( void *record_buffer , struct MemField *where_field_array , size_t where_field_array_count )
{
	list<struct MemDataPage*>::iterator	it ;
	struct MemDataPage			*record_datapage = NULL ;
	char					*record_data = NULL ;
	uint32_t				used_bitmap ;
	char					*record_dataunit = NULL ;
	int					result ;
	
	for( it = record_data_pages.begin() ; it != record_data_pages.end() ; it++ )
	{
		record_datapage = (*it) ;
		
		used_bitmap = 1 << 31 ;
		record_dataunit = record_datapage->dataunit_array_base ;
		while( used_bitmap )
		{
			if( used_bitmap & record_datapage->dataunit_used_bitmap )
			{
				record_data = record_dataunit + sizeof(struct MemRecordDataUnitHead) ;
				result = TestRecordMatched( record_data , where_field_array , where_field_array_count , record_buffer ) ;
				if( result )
					return record_dataunit;
			}
			
			used_bitmap >>= 1 ;
			record_dataunit += record_datapage->dataunit_size ;
		}
	}
	
	return NULL;
}

MemIndex *MemTable::CreateIndex( string index_name , MemIndexType index_type , ... )
{
	MemIndex	*index = NULL ;
	va_list		valist ;
	bool		bret ;
	
	index = new MemIndex( db , index_name , index_type ) ;
	if( index == NULL )
	{
		db->SetError( MemDatabaseError::MDB_ERROR_ALLOC );
		return NULL;
	}
	
	va_start( valist , index_type );
	bret = index->Init( valist ) ;
	va_end( valist );
	if( bret != true )
	{
		delete index;
		return NULL;
	}
	
	indexs.insert( make_pair(index_name,index) );
	
	return index;
}

bool MemTable::DropIndex( string index_name )
{
	MemIndex	*index = NULL ;
	
	index = QueryIndex( index_name ) ;
	if( index == NULL )
	{
		db->SetError( MemDatabaseError::MDB_ERROR_INDEX_NOT_FOUND );
		return false;
	}
	
	indexs.erase( index_name );
	delete index;
	
	return true;
}

bool MemTable::DropIndex( MemIndex *index )
{
	return DropIndex( index->GetIndexName() );
}

MemIndex *MemTable::QueryIndex( string index_name )
{
	return indexs.at( index_name );
}

bool MemTable::Insert( void *record_buffer )
{
	struct MemDataPage			*record_datapage = NULL ;
	char					*record_dataunit = NULL ;
	struct MemRecordDataUnitHead		*record_dataunit_head = NULL ;
	char					*record_data = NULL ;
	struct MemRecordDataUnitTail		*dataunit_tail = NULL ;
	MemIndex				*index = NULL ;
	bool					bret ;
	
	if( record_data_pages.empty() )
		record_datapage = NULL ;
	else
		record_datapage = record_data_pages.back() ;
	if( record_datapage == NULL || IsFull(record_datapage) )
	{
#if MDB_TRACE
		if( record_datapage == NULL )
			cout << "TRACE - MemTable::Insert : record_datapage not found" << endl ;
		else
			cout << "TRACE - MemTable::Insert : record_datapage[" << record_datapage << "] end record data page full" << endl ;
#endif
		record_datapage = CreateDataPage( this , sizeof(struct MemRecordDataUnitHead) + record_size + sizeof(struct MemRecordDataUnitTail) ) ;
		if( record_datapage == NULL )
		{
#if MDB_TRACE
			cout << "TRACE - MemTable::Insert : CreateDataPage failed" << endl ;
#endif
			db->SetError( MemDatabaseError::MDB_ERROR_ALLOC );
			return false;
		}
#if MDB_TRACE
		else
		{
			cout << "TRACE - MemTable::Insert : CreateDataPage ok" << endl ;
		}
#endif
		
#if MDB_TRACE
		cout << "TRACE - MemTable::Insert : record_data_pages.push_back record_datapage[" << record_datapage << "]" << endl ;
#endif
		record_data_pages.push_back( record_datapage );
	}
#if MDB_TRACE
	else
	{
		cout << "TRACE - MemTable::Insert : end record data page not full" << endl ;
	}
#endif
	
	record_dataunit = GetUnusedDataUnit( record_datapage ) ;
	record_dataunit_head = (struct MemRecordDataUnitHead *)record_dataunit ;
	record_data = record_dataunit + sizeof(struct MemRecordDataUnitHead) ;
	dataunit_tail = (struct MemRecordDataUnitTail *)(record_data+record_size) ;
	
	record_dataunit_head->record_no = max_record_no ;
	max_record_no++;
	
#if MDB_TRACE
	cout << "TRACE - MemTable::Insert : memcpy to record_data[" << static_cast<void*>(record_data) << "] record_size[" << record_size << "]" << endl ;
	MemDatabaseUtil::printhex( (char*)record_buffer , record_size );
	cout << endl ;
#endif
	memcpy( record_data , record_buffer , record_size );
	
	dataunit_tail->record_datapage = record_datapage ;
	dataunit_tail->insert_id = 0 ;
	dataunit_tail->delete_id = 0 ;
	
	for( unordered_map<string,MemIndex*>::iterator it = indexs.begin() ; it != indexs.end() ; it++ )
	{
		index = it->second ;
#if MDB_TRACE
		cout << "TRACE - MemTable::Insert : index->MaintentIndexOnInsert ..." << endl ;
#endif
		bret = index->MaintentIndexOnInsert( record_dataunit ) ;
		if( bret != true )
		{
#if MDB_TRACE
			cout << "TRACE - MemTable::Insert : index->MaintentIndexOnInsert failed" << endl ;
#endif
			/* TODO */
			/* ... */
			return false;
		}
#if MDB_TRACE
		else
		{
			cout << "TRACE - MemTable::Insert : index->MaintentIndexOnInsert ok" << endl ;
		}
#endif
	}
	
	return true;
}

bool MemTable::Select( void *record_buffer , ... )
{
	va_list			valist ;
	struct MemField		select_field_array[ MDB_SELECT_FIELD_ARRAY_MAXCOUNT ] ;
	size_t			select_field_array_count ;
	struct MemField		where_field_array[ MDB_WHERE_INDEX_FIELD_ARRAY_MAXCOUNT ] ;
	size_t			where_field_array_count ;
	MemIndex		*index = NULL ;
	MemIndexDataUnit	*index_dataunit = NULL ;
	char			*record_dataunit = NULL ;
	char			*record_data = NULL ;
	size_t			select_field_array_no ;
	bool			bret ;
	
	va_start( valist , record_buffer );
	
#if MDB_TRACE
	cout << "TRACE - MemTable::Select : convert select field array ..." << endl ;
#endif
	bret = MemDatabaseUtil::ConvertArgsToArray( valist , select_field_array , sizeof(select_field_array)/sizeof(select_field_array[0]) , & (select_field_array_count) ) ;
	if( bret != true )
	{
#if MDB_TRACE
		cout << "TRACE - MemTable::Select : convert select field array failed" << endl ;
#endif
		return false;
	}
#if MDB_TRACE
	else
	{
		cout << "TRACE - MemTable::Select : convert select field array ok" << endl ;
	}
#endif
	
#if MDB_TRACE
	cout << "TRACE - MemTable::Select : convert where field array ..." << endl ;
#endif
	bret = MemDatabaseUtil::ConvertArgsToArray( valist , where_field_array , sizeof(where_field_array)/sizeof(where_field_array[0]) , & (where_field_array_count) ) ;
	if( bret != true )
	{
#if MDB_TRACE
		cout << "TRACE - MemTable::Select : convert where field array failed" << endl ;
#endif
		return false;
	}
#if MDB_TRACE
	else
	{
		cout << "TRACE - MemTable::Select : convert where field array ok" << endl ;
	}
#endif
	
	va_end( valist );
	
#if MDB_TRACE
	cout << "TRACE - MemTable::Select : QueryExecuteSchedule ..." << endl ;
#endif
	index = QueryExecuteSchedule( where_field_array , where_field_array_count ) ;
	if( index )
	{
#if MDB_TRACE
		cout << "TRACE - MemTable::Select : QueryExecuteSchedule ok , index[" << index->GetIndexName() << "]" << endl ;
#endif
		
#if MDB_TRACE
		cout << "TRACE - MemTable::Select : QueryIndexDataUnitTreeNode ..." << endl ;
#endif
		index_dataunit = index->QueryIndexDataUnitTreeNode( (char*)record_buffer ) ;
		if( index_dataunit == NULL )
		{
#if MDB_TRACE
			cout << "TRACE - MemTable::Select : QueryIndexDataUnitTreeNode index data not found" << endl ;
#endif
			db->SetError( MemDatabaseError::MDB_INFO_SQL_NOT_FOUND );
			return false;
		}
#if MDB_TRACE
		else
		{
			cout << "TRACE - MemTable::Select : QueryIndexDataUnitTreeNode ok" << endl ;
		}
#endif
		
		record_dataunit = index_dataunit->record_dataunit ;
	}
	else
	{
#if MDB_TRACE
		cout << "TRACE - MemTable::Select : QueryExecuteSchedule ok , no index matched" << endl ;
#endif
		
		record_dataunit = QueryRecordWithoutIndex( record_buffer , where_field_array , where_field_array_count ) ;
		if( record_dataunit == NULL )
		{
#if MDB_TRACE
			cout << "TRACE - MemTable::Select : QueryRecordWithoutIndex record data not found" << endl ;
#endif
			db->SetError( MemDatabaseError::MDB_INFO_SQL_NOT_FOUND );
			return false;
		}
#if MDB_TRACE
		else
		{
			cout << "TRACE - MemTable::Select : QueryRecordWithoutIndex ok" << endl ;
		}
#endif
	}
	
#if MDB_TRACE
	cout << "TRACE - MemTable::Select : record_dataunit[" << static_cast<void*>(record_dataunit) << "] ok" << endl ;
#endif
	
	record_data = record_dataunit + sizeof(struct MemRecordDataUnitHead) ;
	
	for( select_field_array_no = 0 ; select_field_array_no < select_field_array_count ; select_field_array_no++ )
	{
#if MDB_TRACE
		cout << "TRACE - MemTable::Select : no[" << select_field_array_no << "] memcpy .field_offset[" << select_field_array[select_field_array_no].field_offset << "] .field_size[" << select_field_array[select_field_array_no].field_size << "]" << endl ;
		MemDatabaseUtil::printhex( (char*)record_buffer+select_field_array[select_field_array_no].field_offset , select_field_array[select_field_array_no].field_size );
		cout << endl ;
#endif
		memcpy( (char*)record_buffer+select_field_array[select_field_array_no].field_offset , record_data+select_field_array[select_field_array_no].field_offset , select_field_array[select_field_array_no].field_size );
	}
	
	return true;
}

